/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Segment;

import Core.SqlConnection;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import org.pircbotx.Channel;
import org.pircbotx.PircBotX;
import org.pircbotx.User;
import org.pircbotx.hooks.ListenerAdapter;
import org.pircbotx.hooks.events.KickEvent;
import org.pircbotx.hooks.events.MessageEvent;

/**
 *
 * @author tangd
 */
public class SegmentModule extends ListenerAdapter {
    //Columns (user) (type) (count) (last host)
    private PreparedStatement getCount;
    private PreparedStatement updateOrInsert;
    private LinkedHashSet<String> channels;
    private long segmentBaseTime = 43200;
    private long programBaseTime = 172800;
    private long maxBan = Math.round(2.62974e6);
    private Connection c;
    private SqlConnection sql;
    private String table;
    public SegmentModule(LinkedHashSet<String> enabledChannels, SqlConnection c, String table) {
        this.sql = c;
            this.table = table;
//            getCount = c.prepareStatement("SELECT * FROM "+table+" WHERE `username`=? AND `type`=?");
//            updateOrInsert = c.prepareStatement("INSERT INTO "+table+" VALUES (?,?,1,?) ON DUPLICATE KEY UPDATE `occurrences`=`occurrences`+1, `lasthost`=?");
            channels = enabledChannels;
        
    }
    public SegmentModule(LinkedHashSet<String> enabledChannels, SqlConnection c, String table, long segmentTime, long programTime, long maxBan) {
        this(enabledChannels, c, table);
        segmentBaseTime = segmentTime;
        programBaseTime = programTime;
        this.maxBan = maxBan;
    }
    private void reconnect() throws SQLException {
        c = sql.getConnection();
        getCount = c.prepareStatement("SELECT * FROM "+table+" WHERE `username`=? AND `type`=?");
        updateOrInsert = c.prepareStatement("INSERT INTO "+table+" VALUES (?,?,1,?) ON DUPLICATE KEY UPDATE `occurrences`=`occurrences`+1, `lasthost`=?");
        
    }
    public void onMessage(MessageEvent event) {
       // System.err.println(event.getChannel().getName());
        if(channels.contains(event.getChannel().getName())) {
            //If the channel is not in an active channel, ignore
            long banTime = 0;
            String occurence = "";
 //           System.err.println("Matched channel");
            if(event.getMessage().trim().matches(("!segment\\s+\\S+"))) {
                //Check segment
 //               System.err.println("Matched Message: Segment");
                PircBotX bot = event.getBot();
                if(!hasAccess(event.getUser(), event.getChannel())) {
                    bot.kick(event.getChannel(), event.getUser(), "use tell |user about segmenting");
                    return;
                }
                String userString = event.getMessage().trim().split("\\s+")[1];
                if(!userString.startsWith("|"))
                    userString = "|" + userString;
                synchronized (this) {
                    User user = bot.getUser(userString);
                    if (!user.getChannels().contains(event.getChannel())) {
                        bot.sendNotice(event.getUser(), "Error: user " + userString + " not found");
                        return;
                    }
                    bot.sendMessage(user, "Segmenting is when your computer splits a file to download into a bunch of little files and downloads them separately.  It's meant to increase speed but doesn't work when you're on a network as fast as ours, and actually slows your download.  Also, it theoretically damages hard drives, and definitely slows computers uploading the files. | To disable in DC++: Uncheck file-> settings-> advanced-> Enable segmented downloads");
                    execute(bot, event.getChannel(), user, event.getUser(), segmentBaseTime, 0);
                    try {
                    Thread.sleep(2000);
                    } catch(Exception e) {}

//                    event.getChannel().getUsers().remove(user);
                }
            }
            else if(event.getMessage().trim().matches(("!program\\s+\\S+"))) {
                //Check program
 //               System.err.println("Matched Message: Program");
                PircBotX bot = event.getBot();
                if(!hasAccess(event.getUser(), event.getChannel())) {
                    bot.kick(event.getChannel(), event.getUser(), "DENIED");
                    return;
                }
                String userString = event.getMessage().trim().split("\\s+")[1];
                if(!userString.startsWith("|"))
                    userString = "|" + userString;
                User user = bot.getUser(userString);
                if(!event.getChannel().getUsers().contains(user)) {
                    bot.sendNotice(event.getUser(), "Error: user "+userString+" not found");
                    return;
                }
                banTime = programBaseTime;
                execute(bot, event.getChannel(), user, event.getUser(), banTime, 1);
                bot.sendMessage(user, "You have been banned because your share violates one or more rules.  Please check that you are not doing one of the following : 1. Sharing personal information (SSN, credit cards, etc) 2.  Sharing useless files to avoid minimum share");
            }
            
        }
    }

    private void execute(PircBotX b, Channel c, User target, User source, long baseTime, int mode) {
        String type = mode==0 ? "segment" : "program";
        String reason;
        int occurrence = 1;
        long banTime = baseTime;
        try {
            reconnect();
            this.c.setAutoCommit(true);
            getCount.setString(1, target.getNick());
            getCount.setString(2, type);
            ResultSet results = getCount.executeQuery();
            if(results.next()) {
                occurrence = 1+results.getInt("occurrences");
                banTime *= Math.round(Math.pow(2, occurrence-1));
            }
            //c.prepareStatement("INSERT INTO "+table+" VALUES (?,?,1,?) ON DUPLICATE KEY UPDATE `count`=`count`+1, `lasthost`=?");
            updateOrInsert.setString(1, target.getNick());
            updateOrInsert.setString(2, type);
            updateOrInsert.setString(3, target.getHostmask());
            updateOrInsert.setString(4, target.getHostmask());
            updateOrInsert.execute();
            reason = ""+occurrence;
            this.c.close();
        }
        catch(SQLException sqlEx) {
            reason = "?";
            sqlEx.printStackTrace();
        }
        if(mode==0) {
            reason = String.format("Please disable segmenting ( http://wiki.dtella.org/wiki/Disabling_Segmenting ).  Occurence #%s, kicked by %s", reason, source.getNick());
        }
        else {
            reason = String.format("Please fix your share to comply with dtella rules (No junk/unusable files).  Occurence #%s, kicked by %s", reason, source.getNick());
        }
        timeKickBan(b, c, target.getNick(), banTime, reason);
    }
    private void timeKickBan(PircBotX b, Channel c, String user, long time, String reason) {
        User u = b.getUser(user);
        if(u==null)
            return;
        time = time > maxBan ? maxBan : time;
        String banMask = String.format("|*!*@%s", u.getHostmask());
        b.sendRawLine(String.format("TBAN %s %ds %s", c.getName(), time, banMask));
        b.kick(c, u, reason);
    }
    private boolean hasAccess(User u, Channel c) {
        return c.isHalfOp(u) || c.isOp(u) || c.isOwner(u) || c.isSuperOp(u) || (c.hasVoice(u) && u.isIdentified());
    }
}
